package cn.jja8.bukkit.bukkitwindowtool.window;

import cn.jja8.bukkit.bukkitwindowtool.window.error.NullInventory;
import cn.jja8.bukkit.bukkitwindowtool.window.error.NullPlayer;
import cn.jja8.bukkit.bukkitwindowtool.window.error.NullPlugin;
import cn.jja8.bukkit.bukkitwindowtool.window.error.NullWindow;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.plugin.Plugin;

import java.util.HashMap;
import java.util.Map;

/**
 * 一个window的管理器，使用时建议只new一个。因为每new一个都会注册一个监听器。
 * */
public class WindowManger implements Listener {
    Plugin plugin;
    Map<Player,Window> windowMap = new HashMap<>();
    Map<Player, InventoryView> inventoryMap = new HashMap<>();
    /**
     * 非必要请不要new多个WindowManger，建议一个插件中只使用一个。
     * */
    public WindowManger(Plugin plugin) {
        if (plugin==null){
            throw new NullPlugin("plugin不能为null");
        }
        this.plugin = plugin;

        Bukkit.getServer().getPluginManager().registerEvents(this,plugin);
    }

    @EventHandler
    void PlayerQuitEvent(PlayerQuitEvent playerQuitEvent){//玩家离开服务器的监听器
        Player player = playerQuitEvent.getPlayer();
        Window window = windowMap.remove(player);
        InventoryView inventoryView = inventoryMap.remove(player);
        if (window!=null&&inventoryView!=null){
            window.beClose(player,inventoryView);
        }
    }

    @EventHandler
    void InventoryCloseEvent(InventoryCloseEvent inventoryCloseEvent){//物品栏被关闭
        HumanEntity who = inventoryCloseEvent.getPlayer();
        if (!(who instanceof Player)){
            return;
        }
        InventoryView inventoryView = inventoryCloseEvent.getView();
        if (!inventoryMap.remove(who,inventoryView)) {
            return;
        }
        Window window = windowMap.remove(who);
        if (window!=null){
            window.beClose((Player) who,inventoryView);
        }
    }

    @EventHandler(priority = EventPriority.LOWEST)
    void InventoryOpenEvent(InventoryOpenEvent inventoryOpenEvent){//物品栏打开事件
        if (inventoryOpenEvent.isCancelled()){
            return;//被取消了就不用处理了
        }

        HumanEntity who = inventoryOpenEvent.getPlayer();
        if (!(who instanceof Player)){
            return;
        }

        Window beCloseWindow = windowMap.remove(who);
        InventoryView beCloseInventoryView = inventoryMap.remove(who);

        if (beCloseWindow!=null&&beCloseInventoryView!=null){
            //这个异常不用处理了，因为上面bukkit会处理的，而且也是最后一条语句了
            beCloseWindow.beCover((Player) who,beCloseInventoryView,inventoryOpenEvent.getView());
        }
    }

    @EventHandler
    void InventoryClickEvent(InventoryClickEvent inventoryClickEvent){//玩家点击物品栏
        HumanEntity who = inventoryClickEvent.getWhoClicked();
        if (!(who instanceof Player)){
            return;
        }
        Player player = (Player) who;
        if (inventoryMap.get(player)!=inventoryClickEvent.getView()){
            return;
        }
        windowMap.get(player).click(inventoryClickEvent,player);
    }

    /**
     * 给玩家打开界面
     * */
    public void openWindow(Window window, Player player){
        if (player==null){
            throw new NullPlayer("打开界面没有指定玩家");
        }
        if (window==null){
            throw new NullWindow("打开界面没有指定window");
        }
        Inventory inventory = window.getInventory();
        if (inventory==null){
            throw new NullInventory("window没有返回inventory");
        }
        InventoryView inventoryView = player.openInventory(inventory);//这里会跳到InventoryOpenEvent方法处理物品栏打开事件
        if (inventoryView==null){
            //如果被其他插件取消了
            return;
        }

        windowMap.put(player,window);
        inventoryMap.put(player,inventoryView);

        try {
            window.beOpen(player,inventoryView);
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }
    }

}
